const validate = require("validate.js");
const blogTypeModel = require("../dao/model/blogTypeModel");
const {ValidationError} = require("../utils/errors");
const {addBlogDao, getBlogListDao, getBlogByIdDao, updateBlogDao, deleteBlogDao} = require("../dao/blogDao");
const {addBlogCountDao, findOneBlogTypeDao} = require("../dao/blogTypeDao");
const {formatResponse, handleDataPattern, handleTOC} = require("../utils/tool");
const {deleteMessageByBlogIdDao} = require("../dao/messageDao");

// 扩展验证规则
validate.validators.categoryIdIsExist = async function (categoryId) {
    const blogTypeInfo = await blogTypeModel.findByPk(categoryId);
    if (blogTypeInfo) {
        return
    }
    return "CategoryId Is Not Exist";
}

// 添加文章
module.exports.addBlogService = async (newBlogInfo) => {
    // 处理 toc 格式
    newBlogInfo = handleTOC(newBlogInfo);
    // 将处理好的 toc 格式转为 字符串
    newBlogInfo.toc = JSON.stringify(newBlogInfo.toc);
    // console.log(newBlogInfo)
    // 初始化新文章的其他信息
    newBlogInfo.scanNumber = 0
    newBlogInfo.commentNumber = 0
    // 定义校验规则
    const blogRule = {
        title: {
            presence: {
                allowEmpty: false
            },
            type: "string",
        },
        description: {
            presence: {
                allowEmpty: true
            },
            type: "string",
        },
        toc: {
            presence: {
                allowEmpty: true
            },
            type: "string",
        },
        htmlContent: {
            presence: {
                allowEmpty: false
            },
            type: "string",
        },
        thumb: {
            presence: {
                allowEmpty: true
            },
            type: "string",
        },
        scanNumber: {
            presence: {
                allowEmpty: false
            },
            type: "integer",
        },
        commentNumber: {
            presence: {
                allowEmpty: false
            },
            type: "integer",
        },
        createDate: {
            presence: {
                allowEmpty: false
            },
            type: "string",
        },
        categoryId: {
            presence: true,
            type: "integer",
            categoryIdIsExist: true,
        }
    }
    // 数据校验
    try {
        // 扩展的验证规则里面涉及异步操作
        await validate.async(newBlogInfo, blogRule);
        const data = await addBlogDao(newBlogInfo);
        // 文章新增 对应的文章分类也需要新增
        await addBlogCountDao(newBlogInfo.categoryId);
        return formatResponse(0, '', data);
    } catch (error) {
        console.log(error);
        // 验证未通过
        throw new ValidationError("数据验证失败");
    }
}
// 分页获取文章
module.exports.getBlogListService = async (pageInfo) => {
    const data = await getBlogListDao(pageInfo)
    const rows = data.rows
    // console.log(data.rows)
    // const rows = handleDataPattern(data.rows)
    // // 还原 toc 格式
    // rows.forEach(item => {
    //     item.toc = JSON.parse(item.toc)
    // })
    return formatResponse(0, '', {
        total: data.count,
        rows: rows
    })
}
// 获取某篇文章
module.exports.getBlogByIdService = async function (id, token) {
    const result = await getBlogByIdDao(id);
    // 处理 toc
    result.dataValues.toc = JSON.parse(result.dataValues.toc)
    // 前台不需要 token 浏览数需要自增 后台需要 token 浏览数不需要自增
    if (!token) {
        result.scanNumber++
        await result.save()
    }
    return formatResponse(0, '', result.dataValues)
}
// 修改某篇文章
module.exports.updateBlogService = async function (id, blogInfo) {
    // 判断正文有没有改变 正文改变需要重新处理 toc
    if (blogInfo.htmlContent) {
        // 处理 toc 格式
        blogInfo = handleTOC(blogInfo);
        // 将处理好的 toc 格式转为 字符串
        blogInfo.toc = JSON.stringify(blogInfo.toc);
    }
    // 对应的文章分类的文章数量也需要改变
    // 获取原始的文章数据
    const {dataValues} =  await getBlogByIdDao(id)
    // 修改后的文章分类id和原始文章分类id不一致
    if (dataValues.categoryId !== blogInfo.categoryId) {
        // 如果分类改变 需要减少原分类的文章数量
        const categoryInfo = await findOneBlogTypeDao(dataValues.categoryId);
        categoryInfo.articleCount > 0 ? categoryInfo.articleCount-- : categoryInfo.articleCount = 0;
        await categoryInfo.save()
        // 增加新分类的文章数量
        await addBlogCountDao(blogInfo.categoryId);
    }
    const result = await updateBlogDao(id, blogInfo);
    return formatResponse(0, '', result.dataValues)
}
// 删除某篇文章
module.exports.deleteBlogService = async function (id) {
    const blog = await getBlogByIdDao(id);
    // 根绝文章分类id减少文章数量
    // 这里有一个小坑！categoryInfo必须是原始值 之后才可以 save 因此 findOneBlogTypeDao 不能在里面直接解构返回
    const categoryInfo = await findOneBlogTypeDao(blog.dataValues.categoryId);
    categoryInfo.articleCount > 0 ? categoryInfo.articleCount-- : categoryInfo.articleCount = 0;
    await categoryInfo.save()
    await deleteBlogDao(id)
    // 该文章下的所有评论也会一并被删除
    await deleteMessageByBlogIdDao(id);
    return formatResponse(0, '删除文章成功', {})
}